﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MovieRental.Entities;
using MovieRental.DataInterfaces;
using MovieRental.BuisnessComponents.Exceptions;
using MovieRental.BuisnessComponents.Base;
using MovieRental.GeneralDataExceptions;

namespace MovieRental.BuisnessComponents
{
    public class EditionComponent : BaseSetComponent<EditionInfo, Guid, IEditionRepository>
    {
        public EditionComponent(IEditionRepository repository)
            : base(repository)
        {
        }

        protected override bool Equals(EditionInfo obj1, EditionInfo obj2)
        {
            return (obj1.MediaTypeId == obj2.MediaTypeId &&
                obj1.MovieId == obj2.MovieId &&
                obj1.Publisher == obj2.Publisher);
        }

        public bool VerifyPricePerDay(double price)
        {
            return (price > 0);
        }

        public bool VerifyQuantity(int quantity, Guid editionId)
        {
            EditionInfo edition;
            try
            {
                edition = Repository.Load(editionId);
            }
            catch (ItemNotFoundException)
            {
                return quantity > 0;               
            }
            int inStock = RemainingQuantity(edition);
            return (quantity - inStock) >= 0;
        }

        public override void Verify(EditionInfo edition)
        {
            if (edition.MediaTypeId == Guid.Empty)
                throw new EmptyFieldException(edition, "MediaTypeId");
            if (edition.MovieId == Guid.Empty)
                throw new EmptyFieldException(edition, "MovieId");
            if (!VerifyPricePerDay(edition.PricePerDay))
                throw new FieldValueRangeException<double>(edition, "PricePerDay", 0, double.MaxValue);
            if (string.IsNullOrWhiteSpace(edition.Publisher))
                throw new EmptyFieldException(edition, "Publisher");
            if (!VerifyQuantity(edition.Quantity, edition.Id))
                throw new FieldValueRangeException<int>(edition, "Quantity", 0, int.MaxValue);
            base.Verify(edition);
        }

        //unused
        public void AddEditionForMovie(MovieInfo movie, string publisher, Guid mediaTypeId, double price, int quantity)
        {
            EditionInfo edition = new EditionInfo()
            {
                Publisher = publisher,
                MediaTypeId = mediaTypeId,
                PricePerDay = price,
                Quantity = quantity,
                MovieId = movie.Id
            };
            AddOrUpdate(edition);
        }

        public override EditionInfo Get(Guid id)
        {
            EditionInfo edition = base.Get(id);
            if (edition == null)
                return null;
            if (edition.DiscountId == Guid.Empty)
                return edition;
            var discountComponent = ComponentFactory.Instance.GetTemporaryDiscountComponent();
            TemporaryDiscountInfo discount = discountComponent.Get(edition.DiscountId);
            if (discount == null)
            {
                edition.DiscountId = Guid.Empty;
                AddOrUpdate(edition);
                OnSourceUpdated();
            }
            return edition;
        }

        public override IEnumerable<EditionInfo> GetAll()
        {
            return base.GetAll().Select(x => Get(x.Id));
        }

        public IEnumerable<EditionInfo> GetAllEditionsForMovie(Guid movieId)
        {
            return Repository.LoadAllForMovie(movieId);
        }

        public IEnumerable<EditionInfo> GetEditionsWithCertainMediaType(Guid movieId, string mediaTypeName)
        {
            var mediaTypeComponent = ComponentFactory.Instance.GetMediaTypeComponent();
            foreach (var edition in GetAll())
            {
                var mediaType = mediaTypeComponent.Get(edition.MediaTypeId);
                if (mediaType == null)
                    continue;
                if (edition.MovieId == movieId && string.Compare(mediaType.Name, mediaTypeName) == 0)
                    yield return edition;
            }
        }

        public IEnumerable<EditionInfo> GetEditionsWithDiscount(Guid discountId)
        {
            return Repository.LoadAll().Where(x => x.DiscountId == discountId);
        }

        public int RemainingQuantity(EditionInfo edition)
        {
            var loanCartComponent = ComponentFactory.Instance.GetLoanCartComponent();
            return edition.Quantity - loanCartComponent.GetNotReturnedLoansForEdition(edition.Id).Count();
        }

        public bool CanDelete(EditionInfo edition)
        {
            return RemainingQuantity(edition) == edition.Quantity;
        }

        public IEnumerable<EditionInfo> GetTopDiscountEditions(int count)
        {
            var discountComponent = ComponentFactory.Instance.GetTemporaryDiscountComponent();
            var query = from edition in GetAll()
                        where edition.DiscountId != Guid.Empty
                        orderby discountComponent.Get(edition.DiscountId).Value descending
                        select edition;
            return query.Take(count);                      
        }

        
    }
}
